﻿using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Aquarinum.Base.Infrastructure.WebSocket.Interface;
using Aquarinum.WebSocekt.Core.Dtos;
using Newtonsoft.Json;

namespace Aquarinum.Base.Infrastructure.WebSocket.InterfaceImp
{
    public class DefaultMessageSendProxy : IMessageSendProxy
    {
        private readonly IClientInfosProvider _clientInfosProvider;
        private readonly WebSocketConnectionContainer _webSocketConnectionContainer;
        private readonly IWebSocketRequestTransfer _webSocketRequestTransfer;

        public DefaultMessageSendProxy(WebSocketConnectionContainer webSocketConnectionContainer,
            IWebSocketRequestTransfer webSocketRequestTransfer, IClientInfosProvider clientInfosProvider)
        {
            _webSocketConnectionContainer = webSocketConnectionContainer;
            _webSocketRequestTransfer = webSocketRequestTransfer;
            _clientInfosProvider = clientInfosProvider;
        }

        public async Task SendMessageAsync(string clientId, string messageJson, long expireSecond = 0,
            bool needPersistence = false, bool needReceipt = false)
        {
            var messageDto = JsonConvert.DeserializeObject<WebsocketMessageDto>(messageJson);
            if (messageDto != null)
            {
                var socket = _webSocketConnectionContainer.GetSocketById(messageDto.To);
                if (socket != null)
                    await _webSocketRequestTransfer
                        .SendMessageAsync(socket, messageDto, expireSecond, needPersistence, needReceipt)
                        .ConfigureAwait(false);
            }
        }

        public Task SendMessageAsync(string clientId, WebsocketMessageDto message, long expireSecond = 0,
            bool needPersistence = false, bool needReceipt = false)
        {
            var socket = _webSocketConnectionContainer.GetSocketById(message.To);

            return Task.Run(() =>
                {
                    if (socket != null)
                        _webSocketRequestTransfer
                            .SendMessageAsync(socket, message, expireSecond, needPersistence, needReceipt)
                            .ConfigureAwait(false);
                }
            );
        }

        public async Task Publish(WebsocketMessageDto message, long expireSecond = 0, bool needPersistence = false,
            bool needReceipt = false)
        {
            var clients = _clientInfosProvider.GetClients();
            foreach (var client in clients)
            {
                var socket = _webSocketConnectionContainer.GetSocketById(client.ClientId);
                if (socket != null)
                    await _webSocketRequestTransfer
                        .SendMessageAsync(socket, message, expireSecond, needPersistence, needReceipt)
                        .ConfigureAwait(false);
            }
        }

        public async Task PublishWithGroup(string groupid, WebsocketMessageDto message, long expireSecond = 0,
            bool needPersistence = false,
            bool needReceipt = false)
        {
            var clients = _clientInfosProvider.GetClientsByGroupId(groupid);
            foreach (var client in clients)
            {
                var socket = _webSocketConnectionContainer.GetSocketById(client.ClientId);
                if (socket != null)
                    await _webSocketRequestTransfer
                        .SendMessageAsync(socket, message, expireSecond, needPersistence, needReceipt)
                        .ConfigureAwait(false);
            }
        }


        public async Task SendReceiptAsync(string clientId, ReceiptMessageDto message)
        {
            var socket = _webSocketConnectionContainer.GetSocketById(clientId);
            if (socket?.State == WebSocketState.Open)
            {
                var serializedMessage = JsonConvert.SerializeObject(message);
                var encodedMessage = Encoding.UTF8.GetBytes(serializedMessage);
                await socket.SendAsync(new ArraySegment<byte>(encodedMessage,
                        0,
                        encodedMessage.Length),
                    WebSocketMessageType.Text,
                    true,
                    CancellationToken.None).ConfigureAwait(false);
            }
        }
    }
}